package com.example.aop;

import com.example.annotation.BusinessLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 日志切面
 * @author long
 * @date 2023/12/8 9:40
 */
@Slf4j
@Aspect
@Service
public class LoggerAspect {

    @Pointcut("@annotation(com.example.annotation.BusinessLog)")
    public void pointCut(){

    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

        String functionDesc = null;

        try{
            // 获取HttpServletRequest
            ServletRequestAttributes servletRequestAttr = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
            assert servletRequestAttr != null;
            HttpServletRequest request = servletRequestAttr.getRequest();

            // 获取功能描述
            Method method = ((MethodSignature)joinPoint.getSignature()).getMethod();
            functionDesc = Optional.ofNullable(method).map(m->m.getDeclaredAnnotation(BusinessLog.class))
                    .map(BusinessLog::functionDesc).orElse(null);
            if(StringUtils.isEmpty(functionDesc)){
                functionDesc = request.getRequestURL().toString();
            }

            // 获取参数
            Predicate<Object> predicate = (args)-> args != null && !(args instanceof HttpServletRequest)
                    && !(args instanceof HttpServletResponse) && !(args instanceof MultipartFile);
            List<Object> argsList = Arrays.stream(joinPoint.getArgs()).filter(predicate).collect(Collectors.toList());

            // 打印日志
            log.info("功能：{},入参：{}",functionDesc,argsList);
        }catch (Exception e){
            log.error("打印日志异常：",e);
        }

        // 执行业务逻辑
        Object result = joinPoint.proceed();

        // 打印日志
        log.info("功能：{},响应：{}",functionDesc,result);

        return result;

    }

}
